package cn.siriusbot.siriuspro.admin.config.database;

import cn.siriusbot.siriuspro.error.MsgException;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.jdbc.datasource.init.ScriptUtils;
import org.springframework.util.ObjectUtils;

import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

@PropertySource(value = "file:${user.dir}/conf/database.properties", ignoreResourceNotFound = true)
@Configuration
@Log4j2
public class DatabaseConfig implements DatabaseManage {

    Type type = Type.Sqlite;

    boolean firstOpen = false;

    @Autowired
    Environment env;

    DataSource mysqlDataSource;
    DataSource sqliteDataSource;

    private Type loadType() {
        String type = env.getProperty("type");
        if (type == null) firstOpen = true; // 首次打开
        String url = env.getProperty("mysql.url");
        String username = env.getProperty("mysql.username");
        String password = env.getProperty("mysql.password");
        if (type == null || type.equals("mysql")) {
            // 判断值是否为空
            if (!ObjectUtils.isEmpty(url) && !ObjectUtils.isEmpty(username) && !ObjectUtils.isEmpty(password)) {
                return Type.Mysql;
            }
        }
        return Type.Sqlite;
    }


    @PostConstruct
    void init() {
        String type = env.getProperty("type");
        if (type == null) firstOpen = true; // 首次打开
        String url = env.getProperty("mysql.url");
        String username = env.getProperty("mysql.username");
        String password = env.getProperty("mysql.password");
        if (type == null || type.equals("mysql")) {
            // 判断值是否为空
            if (!ObjectUtils.isEmpty(url) && !ObjectUtils.isEmpty(username) && !ObjectUtils.isEmpty(password)) {
                this.type = Type.Mysql;
            }
        }
    }


    @Bean(name = "mysqlDataSource")
    public DataSource mysqlDataSource() {
        String type = env.getProperty("type");
        String url = env.getProperty("mysql.url");
        String username = env.getProperty("mysql.username");
        String password = env.getProperty("mysql.password");
        url = url == null ? "" : url;
        username = username == null ? "" : username;
        password = password == null ? "" : password;
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        this.mysqlDataSource = dataSource;
        return dataSource;
    }

    @Bean(name = "sqliteDataSource")
    public DataSource sqliteDataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setUrl("jdbc:sqlite:data/database.db");
        dataSource.setDriverClassName("org.sqlite.JDBC");
        this.sqliteDataSource = dataSource;


        return dataSource;
    }

    /**
     * 获取当前框架t数据库类型
     *
     * @return 数据库
     */
    @Override
    public Type getDataBaseType() {
        return type;
    }

    @Override
    public boolean firstOpen() {
        return firstOpen;
    }

    @Bean
    public MybatisSqlSessionFactoryBean sqlSessionFactory(@Qualifier("mysqlDataSource") DataSource mysqlDataSource, @Qualifier("sqliteDataSource") DataSource sqliteDataSource) throws Exception {
        Type t = loadType();

        MybatisSqlSessionFactoryBean factoryBean = new MybatisSqlSessionFactoryBean();
        factoryBean.setDataSource(t == Type.Mysql ? mysqlDataSource : sqliteDataSource);
        factoryBean.setTypeAliasesPackage("cn.siriusbot.siriuspro.admin.dao");

        if (t == Type.Sqlite) {
            try (final Connection connection = sqliteDataSource.getConnection()) {
                EncodedResource script = new EncodedResource(new ClassPathResource("/sql/sqlite.sql", getClass()), StandardCharsets.UTF_8);
                ScriptUtils.executeSqlScript(connection, script, false, true, "--", ";", "-- SQL Dump", "-- end");
            } catch (Throwable e) {
                log.error(e, e);
                throw new MsgException(500, "导入表数据失败!");
            }
        }

        return factoryBean;
    }

    DataSource tempDataSource;

    @Override
    public boolean connectMysql(String url, String database, String username, String password) {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setUrl(String.format("jdbc:mysql://%s/%s", url, database));
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        try (Connection ignored = dataSource.getConnection()) {
            this.tempDataSource = dataSource;
            this.mysqlInfo = String.format("""
                    type = mysql
                    mysql.url = %s
                    mysql.username = %s
                    mysql.password = %s""", dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword());

            return true;
        } catch (SQLException e) {
            log.error(e + "错误代码->" + e.getSQLState(), e);
            switch (e.getSQLState()) {
                case "28000" -> throw new MsgException(500, "数据库名或账号密码错误");
                case "08S01" -> throw new MsgException(500, "数据库Url连接失败");
                case "42000" -> throw new MsgException(500, "该用户无权限访问该数据库");
                default -> throw new MsgException(500, "未知错误");
            }
        } catch (Throwable e) {
            log.error(e);
            return false;
        }
    }

    /**
     * 导入mysql数据
     */
    @Override
    public void importMysqlData() {
        if (tempDataSource == null) {
            throw new MsgException(500, "还未测试是否连接!");
        }
        try (final Connection connection = tempDataSource.getConnection()) {
            EncodedResource script = new EncodedResource(new ClassPathResource("/sql/sirius.sql", getClass()), StandardCharsets.UTF_8);
            ScriptUtils.executeSqlScript(connection, script, false, true, "--", ";", "-- SQL Dump", "-- end");
        } catch (Throwable e) {
            log.error(e, e);
            throw new MsgException(500, "导入表数据失败!");
        }

    }

    /**
     * mysql插入管理员 账号
     */
    @Override
    public void mysqlAddAdmin(String account, String passwd) {
        if (tempDataSource == null) {
            throw new MsgException(500, "还未测试是否连接!");
        }

        try (final Connection connection = tempDataSource.getConnection()) {
            String sql = "INSERT INTO `admin` (`account`, `passwd`, `power`) VALUES (?, ?, ?)";
            PreparedStatement statement = connection.prepareStatement(sql);
            statement.setString(1, account);
            statement.setString(2, passwd);
            statement.setInt(3, 0);
            int rowsInserted = statement.executeUpdate();
            if (rowsInserted == 0) {
                throw new MsgException(500, "设置管理员账户失败!");
            }
        } catch (Throwable e) {
            log.error(e, e);
            throw new MsgException(500, "设置管理员账户失败!");
        }
    }

    /**
     * mysql插入管理员 账号
     */
    @Override
    public void sqliteAddAdmin(String account, String passwd) {
        if (sqliteDataSource == null) {
            throw new MsgException(500, "还未测试是否连接!");
        }
        // 初始化数据库数据

        try (final Connection connection = sqliteDataSource.getConnection()) {
            String sql = "INSERT INTO `admin` (`account`, `passwd`, `power`) VALUES (?, ?, ?)";
            PreparedStatement statement = connection.prepareStatement(sql);
            statement.setString(1, account);
            statement.setString(2, passwd);
            statement.setInt(3, 0);
            int rowsInserted = statement.executeUpdate();
            if (rowsInserted == 0) {
                throw new MsgException(500, "设置管理员账户失败!");
            }
        } catch (Throwable e) {
            log.error(e, e);
            throw new MsgException(500, "设置管理员账户失败!");
        }
    }


    String mysqlInfo;

    /**
     * 获取mysql数据库的连接配置信息
     *
     * @return mysql数据库的连接配置
     */
    @Override
    public String getMysqlInfo() {
        if (mysqlInfo == null)
            throw new MsgException(500, "构建mysql连接配置出错!");
        return mysqlInfo;
    }

    @Override
    public void setType(Type type) {
        this.type = type;
    }

    @Override
    public void setFirstOpen(boolean b) {
        this.firstOpen = false;
    }

    //    @Bean(name = "mysqlJdbcTemplate")
//    public JdbcTemplate mysqlJdbcTemplate(@Qualifier("mysqlDataSource") DataSource dataSource) {
//        return new JdbcTemplate(dataSource);
//    }
//
//    @Bean(name = "sqliteJdbcTemplate")
//    public JdbcTemplate sqliteJdbcTemplate(@Qualifier("sqliteDataSource") DataSource dataSource) {
//        return new JdbcTemplate(dataSource);
//    }
}